﻿using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.Serialization;

using Dynamic.Core.Utility;
using Dynamic.Core.Extentions;
using Dynamic.Data.Model.DataType;
using Dynamic.Core.Attributes;
using System.ComponentModel;

namespace Dynamic.Data.Model
{
    /// <summary>
    /// 数据实体基类
    /// </summary>
    [Serializable]
    [DataContract]
    public abstract class ModelBase
    {
        private ModelType _modelType;
        private bool _isCopyDisplayValue = true;
        private Dictionary<string, PropertyStatusCode> _propertiesStatusCode;
        private Dictionary<string, string> _displayValues;

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public ModelBase()
        {
            _propertiesStatusCode = new Dictionary<string, PropertyStatusCode>();
            _displayValues = new Dictionary<string, string>();
            this.PropertyChanging += this.OnPropertyChanging;
            this.PropertyChanged += this.OnPropertyChanged;

            this.ModelType = ModelType.MappingEntity;
            this._isCopyDisplayValue = ConfigUtility.GetConfigBoolValue("IsAutoCopyDisplayValues", "是否自动将值转化成字符串存入DisplayValues中", false);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isCopyDisplayValue">是否自动将值转化成字符串存入DisplayValues中</param>
        public ModelBase(bool isCopyDisplayValue)
            : this()
        {
            this._isCopyDisplayValue = isCopyDisplayValue;
        }

        /// <summary>
        /// 从当前实例中得新实例
        /// </summary>
        /// <returns></returns>
        public virtual ModelBase NewEntity()
        {
            return (ModelBase)Activator.CreateInstance(this.GetType());
        }
        #endregion

        #region 属性
        /// <summary>
        /// 数据实体类型
        /// </summary>
        [XmlIgnore]
        [ModelProperty(Name = "ModelType", IsDbfield = false)]
        public ModelType ModelType
        {
            get
            {
                return this._modelType;
            }
            protected set
            {
                this._modelType = value;
            }
        }

        /// <summary>
        /// 属性状态
        /// </summary>
        [XmlIgnore]
        [ModelProperty(Name = "PropertiesStatusCode", IsDbfield = false)]
        public Dictionary<string, PropertyStatusCode> PropertiesStatusCode
        {
            get
            {
                return this._propertiesStatusCode;
            }
        }

        /// <summary>
        /// 显示值：如果设置了自动拷贝显示值则会将所有值转化成字符串；如果设置了非自动拷贝则需要通过手动设置才生效（默认为空字符串）。
        /// </summary>
        [XmlIgnore]
        [ModelProperty(Name = "DisplayValues", IsDbfield = false)]
        public Dictionary<string, string> DisplayValues
        {
            get
            {
                if (this._isCopyDisplayValue && this._displayValues.Count < 1)
                {
                    this.GetPropertiesValues();
                }

                return this._displayValues;
            }
            set
            {
                this._displayValues = value;
            }
        }

        /// <summary>
        /// 设置是否将数据自动拷贝到DisplayValues
        /// </summary>
        [XmlIgnore]
        [ModelProperty(Name = "IsAutoCopyDisplayValues", IsDbfield = false)]
        public bool IsAutoCopyDisplayValues
        {
            get
            {
                return this._isCopyDisplayValue;
            }
            set
            {
                this._isCopyDisplayValue = value;
            }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 得到某个属性的显示值
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetDisplayValue(string name)
        {
            string dv = string.Empty;

            if (this._displayValues.ContainsKey(name))
            {
                dv = this._displayValues[name];
            }
            else
            {
                try
                {
                    dv = this.GetPropertyValue(name).ToString();
                }
                catch
                {
                    //TODO:写入日志
                }
            }

            return dv;
        }

        /// <summary>
        /// 得到实体数据库字段所有显示值
        /// </summary>
        protected void GetPropertiesValues()
        {
            foreach (System.Reflection.PropertyInfo pi in this.GetType().GetProperties())
            {
                object[] atts = pi.GetCustomAttributes(false);
                if (atts.IsNull() || atts.Length < 1)
                {
                    continue;
                }

                foreach (object att in atts)
                {
                    if (!(att is StaticEntityPropertyAttribute))
                    {
                        continue;
                    }

                    StaticEntityPropertyAttribute tmp = (StaticEntityPropertyAttribute)att;
                    if (tmp.IsDbfield)
                    {
                        object obj = pi.GetPropertyValue(pi.Name);
                        if (obj.IsNull())
                        {
                            this._displayValues.Add(pi.Name, string.Empty);
                        }
                        else
                        {
                            this._displayValues.Add(pi.Name, obj.ToString());
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 转化成XML
        /// </summary>
        /// <returns></returns>
        public virtual XmlDocument ToXML()
        {
            XmlDocument xmldoc = new XmlDocument();

            return xmldoc;
        }

        /// <summary>
        /// 转化成Json
        /// </summary>
        /// <returns></returns>
        public virtual string ToJson()
        {
            string reval = string.Empty;

            return reval;
        }
        #endregion
        
        #region 事件

        /// <summary>
        /// 属性改变前事件
        /// </summary>
        public event PropertyChangingEventHandler PropertyChanging;

        /// <summary>
        /// 属性改变后事件
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 关联属性改变前事件
        /// </summary>
        /// <param name="propertyName"></param>
        protected virtual void SendPropertyChanging(string propertyName)
        {
            var handler = PropertyChanging;
            if (handler != null)
                handler(this, new PropertyChangingEventArgs(propertyName));
        }

        /// <summary>
        /// 关联属性改变后事件
        /// </summary>
        /// <param name="propertyName"></param>
        protected virtual void SendPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// 触发属性改变前事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnPropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (e.PropertyName.Length > 0)
            {
                this._propertiesStatusCode[e.PropertyName] = PropertyStatusCode.Changing;
            }
        }

        /// <summary>
        /// 触发属性改变后事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Length > 0)
            {
                this._propertiesStatusCode[e.PropertyName] = PropertyStatusCode.Changed;
            }
        }
        #endregion
    }
}
